package com.sunny.activiti.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.sunny.activiti.common.config.AppConfig;
import com.sunny.activiti.common.util.FileUploadUtils;
import com.sunny.activiti.service.IProcesService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.converter.util.InputStreamProvider;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.impl.util.io.InputStreamSource;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipInputStream;

/**
 * @ClassName: ProcesServiceImpl
 * @Description:
 * @Author: sunt
 * @Date: 2020/5/28 14:55
 * @Version 1.0
 **/@Service
@Slf4j
public class ProcesServiceImpl implements IProcesService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Override
    public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey) {
        return runtimeService.startProcessInstanceByKey(processDefinitionKey,businessKey);
    }

    @Override
    public String upload(MultipartFile multipartFile) throws IOException {
        return FileUploadUtils.upload(AppConfig.getUploadPath()+"/processDefinition" , multipartFile);
    }

    @Override
    public Model uploadStreamAndDeployment(MultipartFile file) throws IOException {
        // 注意：直接使用文件上传方式，act_re_model表不保存流程模型数据。
//        // 获取上传的文件名
//        String fileName = file.getOriginalFilename();
//        // 得到输入流（字节流）对象
//        InputStream fileInputStream = file.getInputStream();
//        // 文件的扩展名
//        String extension = FilenameUtils.getExtension(fileName);
//        Deployment deploy;
//        if (extension.equals("zip")) {
//            ZipInputStream zip = new ZipInputStream(fileInputStream);
//            deploy = repositoryService.createDeployment()//初始化流程
//                    .addZipInputStream(zip)
//                    .deploy();
//        } else {
//            deploy = repositoryService.createDeployment()//初始化流程
//                    .addInputStream(fileName, fileInputStream)
//                    .deploy();
//        }

        BpmnModel bpmnModel = getBpmnModel(file);
        Model model = saveModel(bpmnModel);
        String modelId = model.getId();
        BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
        ObjectNode modelObjectNode = jsonConverter.convertToJson(bpmnModel);
        repositoryService.addModelEditorSource(modelId, modelObjectNode.toString().getBytes(StandardCharsets.UTF_8));
        log.info("导入成功，modelerId={}", modelId);
        return model;


    }

    @Override
    public void exportModel(String modelId, HttpServletResponse response) {
        response.setContentType("text/html; charset=UTF-8"); //转码
        Model modelData = repositoryService.getModel(modelId);
        try {
            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
            JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
            BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
            if (bpmnModel.getProcesses().size() == 0) {
                throw new RuntimeException("未创建流程实例，导出失败！");
            }
            BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
            byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
            ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
            String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
            response.setContentType("application/xml");
            response.setHeader("Content-Disposition", "attachment; filename=" + filename);
            IOUtils.copy(in, response.getOutputStream());
            response.flushBuffer();
            log.info("导出model的xml文件成功：modelerId={}", modelId);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 将 文件转成BPMN模型
     * @param xml
     * @return
     * @throws IOException
     */
    private BpmnModel getBpmnModel(MultipartFile xml) throws IOException {
        InputStream inputStream = xml.getInputStream();
        BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
        InputStreamProvider inputStreamProvider = new InputStreamSource(inputStream);
        BpmnModel bpmnModel = bpmnXMLConverter.convertToBpmnModel(inputStreamProvider, true, false, "UTF-8");
        return bpmnModel;
    }


    private Model saveModel(BpmnModel bpmnModel) {
        Process process = bpmnModel.getProcesses().get(0);
        String name = process.getName();
        String key = process.getId();
        Model model = repositoryService.newModel();
        model.setName(name);
        model.setKey(key);
        repositoryService.saveModel(model);
        return model;
    }

}
